<?php
// +----------------------------------------------------------------------
// | snake
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2022 http://baiyf.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: NickBai <1902822973@qq.com>
// +----------------------------------------------------------------------
namespace app\common\logic;

use think\Db;
use think\facade\Log;

class GoodsLogic extends BaseLogic
{
    public function __construct($tableName = 'Goods'){
        parent::__construct($tableName);
    }
    public function _getCategorySelectData(array $where){
        $field[] = 'id AS id';
        $field[] = 'cat_name AS text';
        $field[] = 'parent_id';
        $where[] = ['delete_time','<',1];
        $dataList = Db::name('Category')->where($where)->field(join(',',$field))->select();
        return $dataList;
    }
    public function _getGoodsCategory($projectId = 0){
        $field[] = 'id AS id';
        $field[] = 'cat_name AS cat_name';
        $field[] = 'parent_id';
        $where[] = ['model_id','=',4];
        $where[] = ['delete_time','<',1];
        if($projectId > 0){
            $where[] = ['project_id','=',$projectId];
        }
        $dataList = Db::name('Category')->where($where)->field(join(',',$field))->select();
        return $dataList;
    }

    public function _getGoodsPager($where, $offset = 0, $limit = 0,$order = '',$isDel = 0){
        $tableDb = Db::name('Goods');

        $field[] = 'g.*';

        //带软删除 $isDel = 1 查询出已经删除了的数据
        if(!empty($isDel)){
            $where[] = ['g.delete_time','>',0];
        }
        else{
            $where[] = ['g.delete_time','<',1];
        }

        if (empty($order)) {
            $order = 'g.display_sort DESC,g.id ASC';
        }

        $tableDb->alias('g')->field(join(',',$field))
//            ->join('__GOODS_OPTION__ go','go.goods_id = g.id','LEFT')
            ->where($where)->order($order);

        if($limit > 0){
            $tableDb->limit($offset, $limit);
        }

        return $tableDb->select();
    }

    public function _getGoodsPagerCountByWhere($where = [],$isDel = 0){
        $tableDb = Db::name('Goods');
        //带软删除
        if(!empty($isDel)){
            $where[] = ['g.delete_time','>',0];
        }
        else{
            $where[] = ['g.delete_time','<',1];
        }
        return $tableDb->alias('g')
//            ->join('__GOODS_OPTION__ go','go.goods_id = g.id','LEFT')
            ->where($where)->count();
    }

    /**
     * 获取状态组的数量
     * @param array $showArr
     * @return array
     */
    public function _getGoodsShowNum(array $showArr){
        $num = [];
        foreach ($showArr as $item) {
            $num[$item] = $this->_getGoodsShowNumByWhere(getGoodsWhere($item));
        }
        return $num;
    }
    /**
     * 获取某个状态的数量
     * @param $where
     * @return float|string
     */
    public function _getGoodsShowNumByWhere($where){
        return Db::name('Goods')->alias('g')
            ->where($where)->count();
    }

    /**
     * 获取 GoodsOption 表未删除 单条 数据 根据 goods_id
     * @param $goodsId
     * @return array|null|\PDOStatement|string|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsOptionModelByGoodsId($goodsId){
        $where[] = ['goods_id','=',$goodsId];
        return $this->_getGoodsOptionModelByWhere($where);
    }

    /**
     * 获取 GoodsOption 表未删除 单条 数据 根据 条件
     * @param array $where
     * @return array|null|\PDOStatement|string|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsOptionModelByWhere(array $where){
        $where[] = ['delete_time','<',1];
        return Db::name('GoodsOption')->where($where)->find();
    }

    /**
     * 获取 GoodsOption 表未删除 多条 数据 根据 $goodsIds
     * @param array $goodsIds
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsOptionListByGoodsIds(array $goodsIds){
        $where[] = ['goods_id','IN',$goodsIds];
        return $this->_getGoodsOptionListByWhere($where);
    }

    /**
     * 获取 GoodsOption 表未删除 多条 数据 根据 条件
     * @param array $where
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsOptionListByWhere(array $where){
        $where[] = ['delete_time','<',1];
        return Db::name('GoodsOption')->where($where)->order('display_sort DESC')->select();
    }

    public function _getGoodsSpecListByGoodsIds(array $goodsIds){
        $where[] = ['goods_id','IN',$goodsIds];
        return $this->_getGoodsSpecListByWhere($where);
    }
    public function _getGoodsSpecListByWhere(array $where){
        $where[] = ['delete_time','<',1];
        return Db::name('GoodsSpec')->where($where)->select();
    }

    public function _getGoodsSpecItemListBySpecIds(array $specIds){
        $where[] = ['spec_id','IN',$specIds];
        return $this->_getGoodsSpecItemListByWhere($where);
    }
    public function _getGoodsSpecItemListByWhere(array $where){
        $where[] = ['delete_time','<',1];
        return Db::name('GoodsSpecItem')->where($where)->select();
    }

    /**
     * 获取商品
     * @param $id
     * @return array|mixed|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsById($id){
        $where[] = ['id','=',$id];
        $where[] = ['delete_time','<',1];
        $goods = Db::name('Goods')->where($where)->find();
        if(empty($goods)){
            return [];
        }

        // 取扩展表
        $goodsExtend = $this->_getFieldOrModelById($id,true,'GoodsExtend');
        if(!empty($goodsExtend)){
            $goods['goods_content'] = $goodsExtend['goods_content'];
        }

        // 多规格版本
        if(!empty($goods['has_option'])){
            $specs = $this->_getGoodsSpecListByGoodsIds([$id]);
            $specIds = [];
            foreach ($specs as $spec) {
                $specIds[] = $spec['id'];
            }
            $specItems = $this->_getGoodsSpecItemListBySpecIds($specIds);
            $fanhui = [];
            foreach ($specs as $spec) {
                $specIds[] = $spec['id'];
                $tmp = [
                    'id' => $spec['id'],
                    'title' => $spec['title'],
                    'items' => [],
                ];
                foreach ($specItems as $specItem) {
                    if($specItem['spec_id'] == $spec['id']){
                        $tmp['items'][] = [
                            'id' => $specItem['id'],
                            'title' => $specItem['title'],
                            'show' => $specItem['is_show'],
                        ];
                    }
                }

                $fanhui[] = $tmp;
            }
            $goods['specs'] = $fanhui;
        }
        else{
            $goods['specs'] = [];
        }
        $options = $this->_getGoodsOptionListByGoodsIds([$id]);
        $goods['options'] = $options;

        // 取价格表 ， 第一版本  goods 表 和 goods_option 表 一对一关系
//        $goodsOption = $this->_getGoodsOptionModelByGoodsId($id);
//        if(!empty($goodsOption)){
//            $goods = array_diff_key_merge($goods,$goodsOption);
//        }

        return $goods;
    }

    /**
     * 获取 商品
     * @param int $id 商品ID
     * @param int $optionId 规格ID 大于则获取
     * @param bool $isGetSpecs 是否获取规格类型
     * @param bool $isGetExtend 是否获取扩展表
     * @return array|null|\PDOStatement|string|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getGoodsByIdAndOptionId($id,$optionId = 0,$isGetSpecs = false,$isGetExtend = false){
        $where[] = ['id','=',$id];
        $where[] = ['delete_time','<',1];
        $goods = Db::name('Goods')->where($where)->find();
        if(empty($goods)){
            return [];
        }

        if (true === $isGetExtend) {
            // 取扩展表
            $goodsExtend = $this->_getFieldOrModelById($id,true,'GoodsExtend');
            if(!empty($goodsExtend)){
                $goods['goods_content'] = $goodsExtend['goods_content'];
            }
        }
        else{
            // 防止出错，会赋空值
            $goods['goods_content'] = '';
        }

        // 多规格版本
        if (!empty($goods['has_option']) && true === $isGetSpecs) {
            $specs = $this->_getGoodsSpecListByGoodsIds([$id]);
            $specIds = [];
            foreach ($specs as $spec) {
                $specIds[] = $spec['id'];
            }
            $specItems = $this->_getGoodsSpecItemListBySpecIds($specIds);
            $fanhui = [];
            foreach ($specs as $spec) {
                $specIds[] = $spec['id'];
                $tmp = [
                    'id' => $spec['id'],
                    'title' => $spec['title'],
                    'items' => [],
                ];
                foreach ($specItems as $specItem) {
                    if($specItem['spec_id'] == $spec['id']){
                        $tmp['items'][] = [
                            'id' => $specItem['id'],
                            'title' => $specItem['title'],
                            'show' => $specItem['is_show'],
                        ];
                    }
                }

                $fanhui[] = $tmp;
            }
            $goods['specs'] = $fanhui;
        }
        else{
            // 防止出错，会赋空值
            $goods['specs'] = [];
        }

        if($optionId > 0){
            $goods['options'] = $this->_getGoodsOptionModelByWhere([['id','=',$optionId]]);
        }
        else{
            $goods['options'] = [];
        }

        return $goods;
    }

    /**
     * 保存 扩展 表
     * @param $goodsId
     * @param $param
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    private function saveGoodsExtend($goodsId,$param){
        $extendData = [
            'goods_content' => $param['goods_content']
        ];
        if(Db::name('GoodsExtend')->where('goods_id',$goodsId)->count() > 0){
            $flag = Db::name('GoodsExtend')->where('goods_id', $goodsId)->update($extendData);
            if (false === $flag) {
                exception('saveGoodsExtend 更新 GoodsExtend 失败 ' . json_encode($extendData,256));
            }
        }
        else{
            $extendData['goods_id'] = $goodsId;
            $flag = Db::name('GoodsExtend')->insert($extendData);
            if (false === $flag) {
                exception('saveGoodsExtend 插入 GoodsExtend 失败 ' . json_encode($extendData,256));
            }
        }
    }

    /**
     * 处理 handleOption 中，需要清理数据的事宜
     * @param $goodsId
     * @param $hasOption
     * @throws \Exception
     */
    private function delOptionByHasOption($goodsId,$hasOption){
        if(empty($hasOption)){
            // 删除 原来设置 的多规格 的数据
            $delWhere[] = ['goods_id','=',$goodsId];
            $delWhere[] = ['specs','<>',config('site.goods_option_specs_val')]; // 删掉不等于 ----- 的规格
            $flag = $this->delGoodsOption($delWhere);
            if (false === $flag) {
                exception('handleOption > delOptionByHasOption 单规格 删除默认的 GoodsOption 失败 $delWhere ' . json_encode($delWhere,256));
            }
        }
        else{
            // 删除默认的 GoodsOption
            $delWhere[] = ['goods_id','=',$goodsId];
            $delWhere[] = ['specs','=',config('site.goods_option_specs_val')];
            $flag = $this->delGoodsOption($delWhere);
            if (false === $flag) {
                exception('handleOption 多规格 删除默认的 GoodsOption 失败 $delWhere ' . json_encode($delWhere,256));
            }
            // 删除 goods_spec 和 goods_spec_item 的数据
            Db::name('GoodsSpec')->where('goods_id',$goodsId)->setField('delete_time',time());
        }
    }

    /**
     * 处理规格
     * @param $goodsId
     * @param $param
     * @return array 返回价格 单位 是 分
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    private function handleOption($goodsId,$param){
        $minPrice = -1;
        $maxPrice = 0;
        $stock = 0;

        $this->delOptionByHasOption($goodsId,$param['has_option']);

        if(empty($param['has_option'])){
            // 未打开 规格 直接写入 goods_option 表 ， goods 表 和 goods_option 表 一对一关系
            $goodsOptionWhere[] = ['delete_time','<',1];
            $goodsOptionWhere[] = ['goods_id','=',$goodsId];
            $goodsOptionWhere[] = ['specs','=',config('site.goods_option_specs_val')];
            $goodsOptionId = Db::name('GoodsOption')->where($goodsOptionWhere)->value('id');
            $goodsOption = [
                'goods_id' => $goodsId,
                'title' => '默认',
                'product_price' => yuanToFen($param['product_price']),
                'market_price' => yuanToFen($param['market_price']),
                'cost_price' => yuanToFen($param['cost_price']),
                'stock' => $param['stock'],
                'weight' => $param['weight'],
                'specs' => config('site.goods_option_specs_val'),
                'goods_sn' => $param['goods_sn'],
                'product_sn' => $param['product_sn'],
            ];
            if(!empty($goodsOptionId)){
                $goodsOption['update_time'] = time();
                $flag = Db::name('GoodsOption')->where('id',$goodsOptionId)->update($goodsOption);
            }
            else{
                $flag = Db::name('GoodsOption')->insertGetId($goodsOption);
            }

            if (false === $flag) {
                exception('handleOption 处理未开启规格 GoodsOption 失败 ' . json_encode($goodsOption,256));
            }

            $minPrice = $param['market_price'];
            $maxPrice = $param['market_price'];
            $stock = $param['stock'];
        }
        else{
            $prices = [];
            // 开启规格
            $specs = json_decode($param['specs'], true);
            if (empty($specs)) {
                exception('handleOption 解析规格specs失败 ' . $param['specs']);
            }
            $specItemIdKeys = [];
            foreach ($specs as $key => $spec){
                $specsData = [
                    'goods_id' => $goodsId,
                    'title' => $spec['title'],
                    'display_sort' => count($specs) - $key,
                ];
                // 插入 主 规格
                $specsData['create_time'] = time();
                $specId = Db::name('GoodsSpec')->insertGetId($specsData);

                if($specId < 1){
                    exception('handleOption 插入 主 规格 失败 ' . json_encode($specsData,256));
                }

                // 处理 子项
                foreach ($spec['items'] as $index => $item) {
                    $specsItemData = [
                        'spec_id' => $specId,
                        'title' => $item['title'],
                        'is_show' => $item['show'],
                        'display_sort' => count($spec['items']) - $index,
                    ];
                    // 插入 子 规格
                    $specsItemData['create_time'] = time();
                    $specsItemId = Db::name('GoodsSpecItem')->insertGetId($specsItemData);

                    if($specsItemId < 1){
                        exception('handleOption 插入 子 规格 失败 ' . json_encode($specsItemData,256));
                    }

                    // 按下标存入 $specsItemId
                    $specItemIdKeys[$key . '_' . $index] = $specsItemId;
                }
            }

            $options = json_decode($param['options'], true);
            if (empty($options)) {
                exception('handleOption 解析规格options失败 ' . $param['options']);
            }
            // 处理选项
            foreach ($options as $key => $option) {
                $tmpTitle = [];
                $tmpSpecs = [];
                foreach ($option['item'] as $item){
                    $tmpTitle[] = $item['title'];
                    $tmpSpecs[] = $specItemIdKeys[$item['index']];
                }
                $optionInput = [
                    'goods_id' => $goodsId,
                    'title' => join(';',$tmpTitle),
                    'product_price' => yuanToFen($option['option_productprice']),
                    'market_price' => yuanToFen($option['option_marketprice']),
                    'cost_price' => yuanToFen($option['option_costprice']),
                    'stock' => $option['option_stock'],
                    'weight' => $option['option_weight'],
                    'goods_sn' => $option['option_goodssn'],
                    'product_sn' => $option['option_productsn'],
                    'display_sort' => count($options) - $key,
                    'specs' => join('_',$tmpSpecs),
                ];

                $optionId = 0;
                if (empty($option['id'])) {
                    // 插入 选项
                    $optionInput['create_time'] = time();
                    $optionId = Db::name('GoodsOption')->insertGetId($optionInput);

                    if($optionId < 1){
                        exception('handleOption 插入 选项 失败 ' . json_encode($optionInput,256));
                    }
                }
                else{
                    $optionId = $option['id'];
                    $optionInput['update_time'] = time();
                    // 更新 子 规格
                    $flag = Db::name('GoodsOption')->where('id',$optionId)->update($optionInput);

                    if (false === $flag) {
                        exception('handleOption 更新 选项 失败 ' . json_encode($optionInput,256));
                    }
                }

                // 加入价格
                $prices[] = $option['option_marketprice'];
                // 汇总 库存
                if(!empty($option['option_stock'])){
                    $stock += $option['option_stock'];
                }
            }

            sort($prices);

            $minPrice = $prices[0];
            $maxPrice = end($prices);
        }
        $priceData = [
            'min_price' => yuanToFen($minPrice),
            'max_price' => yuanToFen($maxPrice),
            'stock' => $stock,
        ];
        // 更新 最小价格 和 最大 价格 库存
        $flag = Db::name('Goods')->where('id',$goodsId)->setField($priceData);

        if (false === $flag) {
            exception('handleOption 更新 最小价格、最大价格、库存 失败 ' . json_encode($priceData,256));
        }
        return [
            'min_price' => $minPrice,
            'max_price' => $maxPrice,
        ];
    }

    /**
     * 保存商品
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function saveGoods($param){
        // 处理分类
        if(!empty($param['cates']) && count($param['cates'])){
            $param['cates'] = ',' . join(',',$param['cates']) . ',';
        }

        //清除空格
        $param = arrayCleanUpSpace($param);
        // 处理后的安全数据
        $postSafeData = [
            'id' => safeShowModelField($param,'id',0),
            'display_sort' => safeShowModelField($param,'display_sort'),
            'goods_name' => safeShowModelField($param,'goods_name'),
            'unit' => safeShowModelField($param,'unit'),
            'type' => safeShowModelField($param,'type'),
            'cates' => safeShowModelField($param,'cates'),

            'market_price' => safeShowModelField($param,'market_price'),
            'product_price' => safeShowModelField($param,'product_price'),
            'cost_price' => safeShowModelField($param,'cost_price'),
            'stock' => safeShowModelField($param,'stock'),
            'weight' => safeShowModelField($param,'weight'),
            'goods_sn' => safeShowModelField($param,'goods_sn'),
            'product_sn' => safeShowModelField($param,'product_sn'),

            'thumbs' => safeShowModelField($param,'thumbs'),
            'sales' => safeShowModelField($param,'sales'),
            'status' => safeShowModelField($param,'status'),
            'stock_cnf' => safeShowModelField($param,'stock_cnf'),
            'has_option' => safeShowModelField($param,'has_option'),
            'goods_content' => safeShowModelField($param,'goods_content'),

            'specs' => safeShowModelField($param,'specs'),
            'options' => safeShowModelField($param,'options'),
        ];

        Db::startTrans();
        try {
            $goodsId = 0;
            if(empty($postSafeData['id'])){
                // 插入
                $goodsInsertData = [
                    'display_sort' => $postSafeData['display_sort'],
                    'goods_name' => $postSafeData['goods_name'],
                    'unit' => $postSafeData['unit'],
                    'type' => $postSafeData['type'],
                    'cates' => $postSafeData['cates'],

                    'thumbs' => $postSafeData['thumbs'],
                    'sales' => $postSafeData['sales'],
                    'status' => $postSafeData['status'],
                    'stock_cnf' => $postSafeData['stock_cnf'],
                    'has_option' => $postSafeData['has_option'],

                    'create_time' => time(),
                ];
                $goodsId = Db::name('Goods')->insertGetId($goodsInsertData);
                if ($goodsId < 1) {
                    exception('插入 Goods 失败 ' . json_encode($goodsInsertData,256));
                }
            }
            else{
                // 更新
                $goodsId = $postSafeData['id'];
                $goodsUpdateData = [
                    'display_sort' => $postSafeData['display_sort'],
                    'goods_name' => $postSafeData['goods_name'],
                    'unit' => $postSafeData['unit'],
                    'type' => $postSafeData['type'],
                    'cates' => $postSafeData['cates'],
                    'thumbs' => $postSafeData['thumbs'],
                    'sales' => $postSafeData['sales'],
                    'status' => $postSafeData['status'],
                    'stock_cnf' => $postSafeData['stock_cnf'],
                    'has_option' => $postSafeData['has_option'],

                    'update_time' => time(),
                ];
                $flag = Db::name('Goods')->where('id',$goodsId)->update($goodsUpdateData);
                if (false === $flag) {
                    exception('更新 Goods 失败 ' . json_encode($goodsUpdateData,256));
                }
            }

            //处理价格、规格相关 ， 第一版本 直接写入 goods_option 表 ， goods 表 和 goods_option 表 一对一关系
            $price = $this->handleOption($goodsId,$postSafeData);
            // 保存 扩展表 详情
            $this->saveGoodsExtend($goodsId,$postSafeData);

            // 提交事务
            Db::commit();

            return $this->retSuccess('编辑商品成功',[
                'goods_id'=>$goodsId,
            ]);
        } catch (\Exception $e) {
            // 统一处理错误日志
            Log::error('GoodsLogic => saveGoods ' . $e->getMessage());
            // 回滚事务
            Db::rollback();

            return $this->retError('编辑商品失败，请联系管理员');
        }
    }

    /**
     * 恢复 商品
     * @param $id
     * @return int
     */
    public function _recoveryGoodsById($id){
        return Db::name('Goods')->where('id',$id)->setField('delete_time',0);
    }

    /**
     * 软删除 规格
     * @param $where
     */
    private function delGoodsOption($where){
        $where[] = ['delete_time','<',1];
        return Db::name('GoodsOption')->where($where)->setField('delete_time',time());
    }

    /**
     * 设置商品属性
     * @param $goodsId
     * @param $attr
     * @param $val
     * @return int
     */
    public function _setGoodsAttr($goodsId,$attr,$val){
        $allowVal = ['1','0'];
        $allowAttr = ['recommand','new','hot'];
        $where[] = ['id','=',$goodsId];
        $where[] = ['delete_time','<',1];
        if(!in_array($val,$allowVal)){
            return false;
        }
        // 不在允许的列，不允许修改
        if(!in_array($attr,$allowAttr)){
            return false;
        }

        return Db::name('Goods')->where($where)->setField('is_' . $attr, $val);
    }
}